﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace ClassProxitator.Messages
{
    public class MethodCallMessage: Message
    {
    	public string MethodName { get; set; }
    	public int TaskId { get; set; }
    	public int InstanceId { get; set; }
    	public object[] Parameters { get; set; }

        public override MessageType MessageType
        {
            get { return MessageType.MethodCall; }
        }

        public override async Task<byte[]> GetContentBytes()
        {
        	using(var s = new MemoryStream())
        	{
                await s.WriteAsync(this.InstanceId).ConfigureAwait(false); // 4bytes: intsance id: int32
                var mname = Encoding.UTF8.GetBytes(this.MethodName);
                await s.WriteAsync(mname.Length).ConfigureAwait(false); // 4bytes: method name lenght: int32
                await s.WriteAsync(mname, 0, mname.Length).ConfigureAwait(false); // n bytes: method name utf-8encoded
                await s.WriteAsync(this.TaskId).ConfigureAwait(false); // 4bytes: task id
                await s.WriteAsync(new byte[] { (byte)this.Parameters.Length }, 0, 1).ConfigureAwait(false); // 1 byte: count of parameters
                if (this.Parameters.Length > 0)
                {
                    var bf = new BinaryFormatter();
                    bf.Serialize(s, new Box(this.Parameters)); // if any, paramaters serializad by binary formatter
                }
                return s.ToArray();
        	}
        }

        public override async Task LoadIn(Stream s)
        {
            this.InstanceId = await s.ReadInt32Async().ConfigureAwait(false);
            var mnamel = await s.ReadInt32Async().ConfigureAwait(false);
            var mnameBuffer = new byte[mnamel];
            await s.ReadAsync(mnameBuffer, 0, mnamel).ConfigureAwait(false);
            var tt = s.ReadInt32Async();
            this.MethodName = Encoding.UTF8.GetString(mnameBuffer);
            this.TaskId = await tt.ConfigureAwait(false);
            var pcount = s.ReadByte();
            if (pcount > 0)
            {
                var bf = new BinaryFormatter();
                this.Parameters = ((Box)bf.Deserialize(s)).Data as object[];
            }
            else Parameters = new object[0];
        }
    }
}
